import 'dart:math' as math;

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:ideology/shared/widgets/code_input/config/editor_metrics.dart';
import 'package:ideology/shared/widgets/code_input/core/editor_controller.dart';
import 'package:ideology/shared/widgets/code_input/core/text_buffer.dart';
import 'package:ideology/shared/widgets/code_input/highlight/highlight_theme.dart';
import 'package:ideology/shared/widgets/code_input/highlight/syntax_highlighter.dart';
import 'package:ideology/shared/widgets/code_input/presentation/painting/editor_painter.dart';
import 'package:ideology/shared/widgets/code_input/presentation/painting/editor_painter_line_number.dart';
import 'package:ideology/shared/widgets/code_input/services/auto_scroller.dart';
import 'package:ideology/shared/widgets/code_input/services/boundary_detector.dart';
import 'package:ideology/shared/widgets/code_input/services/caret_blinker.dart';
import 'package:ideology/shared/widgets/code_input/services/selection_manager.dart';
import 'package:ideology/shared/widgets/code_input/utils/multi_click_tracker.dart';
import 'package:ideology/shared/widgets/code_input/utils/text_layout.dart';

/// **EditorSurface**
///
/// 代码编辑区的交互与绘制“外壳”组件：
/// - 组合绘制器 [EditorPainter]（正文）与 [LineNumberEditorPainter]（行号/滚动条）；
/// - 处理滚轮滚动、点击/拖拽选区、双击/三击选词/选行；
/// - 通过 [AutoScroller] 在拖拽接近边缘时自动滚动；
/// - 与 [EditorController] 协作维护光标与选区，并通过回调向外同步；
/// - 使用 [TextLayout] 在“坐标 ↔ 文本位置”之间转换。
class EditorSurface extends StatefulWidget {
  const EditorSurface({
    super.key,
    required this.buffer, // 文本数据缓冲区
    required this.controller, // 编辑器控制器（光标/选区等）
    required this.metrics, // 尺寸与布局配置
    required this.highlighter, // 语法高亮逻辑
    required this.theme, // 高亮主题
    required this.caretBlinker, // 光标闪烁控制
    required this.focusNode, // 焦点
    required this.textLayout, // 文本布局计算工具
    required this.multiClickTracker, // 多击（双击/三击）检测
    required this.boundary, // 单词/行边界计算
    required this.autoScroller, // 自动滚动（拖拽到边缘时）
    required this.scrollY, // 当前纵向滚动位置
    required this.viewportHeight, // 视口高度
    required this.onScrollYChanged, // 滚动位置变化回调
    required this.onSelectionChanged, // 选区变化回调（用于 IME 同步等）
    required this.onCursorMoved, // 光标移动回调
  });

  /// 文本缓冲（支持高效插入删除的 GapBuffer）
  final TextBuffer buffer;

  /// 光标/选区控制器
  final EditorController controller;

  /// 尺寸与布局配置（行高/边距/行号栏宽等）
  final EditorMetrics metrics;

  /// 语法高亮器与主题
  final SyntaxHighlighter highlighter;
  final HighlightTheme theme;

  /// 光标闪烁与焦点控制
  final CaretBlinker caretBlinker;
  final FocusNode focusNode;

  /// 文本布局与交互工具
  final TextLayout textLayout;
  final MultiClickTracker multiClickTracker;
  final BoundaryDetector boundary;
  final AutoScroller autoScroller;

  /// 滚动状态
  final double scrollY;
  final double viewportHeight;

  /// 对外回调
  final ValueChanged<double> onScrollYChanged;
  final void Function(int? selStart, int? selEnd) onSelectionChanged;
  final ValueChanged<int> onCursorMoved;

  @override
  State<EditorSurface> createState() => _EditorSurfaceState();
}

class _EditorSurfaceState extends State<EditorSurface> {
  /// 仅用于管理“是否正在拖拽选择”等临时状态
  final SelectionManager _sel = SelectionManager();

  // —— 快捷访问器 —— //
  double get _scrollY => widget.scrollY;
  double get _viewportHeight => widget.viewportHeight;
  EditorMetrics get _m => widget.metrics;

  /// 统一设置滚动位置（带边界夹取），并在变化时触发回调
  void _setScroll(double y, double maxScroll) {
    final v = y.clamp(0.0, maxScroll);
    if (v != _scrollY) {
      widget.onScrollYChanged(v);
    }
  }

  /// 仅在**不处于拖拽中**时同步选区给外部（例如 IME），
  /// 避免 IME 反向移动光标影响正在进行的拖拽。
  void _maybeEmitSelectionChanged(String reason) {
    if (_sel.isSelecting) {
      return;
    }
    final s = widget.controller.hasSelection
        ? widget.controller.selectionStart
        : null;
    final e = widget.controller.hasSelection
        ? widget.controller.selectionEnd
        : null;
    widget.onSelectionChanged(s, e);
  }

  /// 基于“本帧有效的 scrollY”重算选区/光标位置，避免坐标与滚动不同步导致的跳闪。
  void _updateSelectionFromLastPointer({
    double? effectiveScrollY,
    String reason = '',
  }) {
    final last = _sel.lastLocal;
    if (last == null) return;

    // 更新布局上下文
    final lines = widget.buffer.getLines();
    widget.textLayout.setLines(lines);

    // 将指针位置转换为文本位置，并写回 controller
    final double sy = effectiveScrollY ?? _scrollY;
    final current = _sel.update(
      last,
      _viewportHeight,
          (clamped) => widget.textLayout.offsetToPosition(clamped, sy),
    );

    // 读取一次（无副作用，只是避免 IDE 标黄）
    final _ = widget.controller.cursorPosition;
    final _ = widget.controller.hasSelection;

    widget.controller.setSelection(_sel.anchor ?? current, current);
    widget.controller.cursorPosition = current; // 以当前命中为准

    _maybeEmitSelectionChanged('Update($reason)');
    widget.onCursorMoved(current);

    if (mounted) setState(() {});
    // 预留：如需下一帧继续收敛，可在此添加逻辑
    WidgetsBinding.instance.addPostFrameCallback((_) {});
  }

  /// 点击（含双击/三击）处理：
  /// - 单击：移动光标、清空选区；
  /// - 双击：按单词边界选中；
  /// - 三击及以上：按行边界选中。
  void _handleTapDown(TapDownDetails d) {
    widget.focusNode.requestFocus();

    // 统计点击次数（用于双击/三击）
    final int clickCount = widget.multiClickTracker.registerTap(
      d.localPosition,
    );

    // 坐标 → 文本位置
    final linesNow = widget.buffer.getLines();
    widget.textLayout.setLines(linesNow);
    final pos = widget.textLayout.offsetToPosition(d.localPosition, _scrollY);

    setState(() {
      final fullText = widget.buffer.getText();

      if (clickCount == 1) {
        // 单击：移动光标、清除选区
        widget.controller.cursorPosition = pos;
        widget.controller.clearSelection();
        _sel.end();
      } else if (clickCount == 2) {
        // 双击：按单词边界选中
        final (s, e) = widget.boundary.wordBoundsAt(fullText, pos);
        widget.controller.setSelection(s, e);
        widget.controller.cursorPosition = e;
        _sel.end();
      } else {
        // 三击（及以上）：整行
        final (s, e) = widget.boundary.lineBoundsAt(fullText, pos);
        widget.controller.setSelection(s, e);
        widget.controller.cursorPosition = e;
        _sel.end();
      }
    });

    _maybeEmitSelectionChanged('TapDown');
    widget.onCursorMoved(widget.controller.cursorPosition);
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // 根据最新行集更新布局上下文
        final lines = widget.buffer.getLines();
        widget.textLayout.setLines(lines);

        // 内容总高度与最大可滚距离
        final contentHeight = _m.padding * 2 + lines.length * _m.lineHeight;
        final maxScroll = math.max(0.0, contentHeight - constraints.maxHeight);

        // 如果当前 scroll 超界，收敛一次并用新 scroll 重算选区，避免跳闪
        if (_scrollY > maxScroll) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            if (!mounted) return;
            _setScroll(maxScroll, maxScroll);
            if (_sel.isSelecting && _sel.lastLocal != null) {
              _updateSelectionFromLastPointer(
                effectiveScrollY: maxScroll,
                reason: 'ClampMaxScroll',
              );
            }
          });
        }

        return Stack(
          children: [
            // 监听滚轮事件：更新 scrollY，并在拖拽中用“新 scroll”即时重算选区
            Listener(
              onPointerSignal: (event) {
                if (event is PointerScrollEvent) {
                  final double newY = math.max(
                    0.0,
                    math.min(maxScroll, _scrollY + event.scrollDelta.dy),
                  );
                  _setScroll(newY, maxScroll);

                  if (_sel.isSelecting && _sel.lastLocal != null) {
                    _updateSelectionFromLastPointer(
                      effectiveScrollY: newY,
                      reason: 'Wheel',
                    );
                  }
                }
              },
              child: GestureDetector(
                behavior: HitTestBehavior.translucent,
                onTapDown: _handleTapDown,

                // 开始拖拽：记录锚点，清空选区，启动自动滚动
                onPanStart: (d) {
                  widget.focusNode.requestFocus();

                  final linesNow = widget.buffer.getLines();
                  widget.textLayout.setLines(linesNow);
                  final anchor = widget.textLayout.offsetToPosition(
                    d.localPosition,
                    _scrollY,
                  );

                  setState(() {
                    _sel.start(d.localPosition, anchor);
                    widget.controller.cursorPosition = anchor;
                    widget.controller.clearSelection();
                  });

                  // 拖拽期间不向外同步选区（避免 IME 拉扯光标）
                  // 自动滚动：滚动后立刻用 newScroll 重算选区与光标
                  widget.autoScroller.ensureRunning(
                    pointerY: () => _sel.lastLocal?.dy ?? _viewportHeight / 2,
                    viewportHeight: () => _viewportHeight,
                    contentHeight: () {
                      final ls = widget.buffer.getLines();
                      return _m.padding * 2 + ls.length * _m.lineHeight;
                    },
                    getScrollY: () => _scrollY,
                    applyScroll: (newScroll) {
                      widget.onScrollYChanged(newScroll);
                      _updateSelectionFromLastPointer(
                        effectiveScrollY: newScroll,
                        reason: 'AutoScrollTick',
                      );
                    },
                  );
                },

                // 拖拽中：持续更新选区与光标位置，同时维持自动滚动
                onPanUpdate: (d) {
                  if (!_sel.isSelecting) return;

                  final linesNow = widget.buffer.getLines();
                  widget.textLayout.setLines(linesNow);

                  final current = _sel.update(
                    d.localPosition,
                    _viewportHeight,
                        (clampedLocal) => widget.textLayout.offsetToPosition(
                      clampedLocal,
                      _scrollY,
                    ),
                  );

                  // 读取一次，避免 IDE 标黄
                  final _ = widget.controller.cursorPosition;

                  setState(() {
                    widget.controller.setSelection(
                      _sel.anchor ?? current,
                      current,
                    );
                    widget.controller.cursorPosition = current;
                  });

                  // 拖拽中不向外同步选区（避免 IME 抢焦）
                  widget.onCursorMoved(current);

                  // 维持自动滚动，滚动后用“新 scroll”重算选区与光标
                  widget.autoScroller.ensureRunning(
                    pointerY: () => _sel.lastLocal?.dy ?? _viewportHeight / 2,
                    viewportHeight: () => _viewportHeight,
                    contentHeight: () {
                      final ls = widget.buffer.getLines();
                      return _m.padding * 2 + ls.length * _m.lineHeight;
                    },
                    getScrollY: () => _scrollY,
                    applyScroll: (newScroll) {
                      widget.onScrollYChanged(newScroll);
                      _updateSelectionFromLastPointer(
                        effectiveScrollY: newScroll,
                        reason: 'AutoScrollTick',
                      );
                    },
                  );
                },

                // 拖拽结束/取消：停止自动滚动，结束临时状态，并同步最终选区到外部
                onPanEnd: (_) {
                  widget.autoScroller.stop();
                  setState(() => _sel.end());
                  _maybeEmitSelectionChanged('PanEnd');
                  widget.onCursorMoved(widget.controller.cursorPosition);
                },
                onPanCancel: () {
                  widget.autoScroller.stop();
                  setState(() => _sel.end());
                  _maybeEmitSelectionChanged('PanCancel');
                  widget.onCursorMoved(widget.controller.cursorPosition);
                },

                child: RepaintBoundary(
                  child: ClipRect(
                    child: CustomPaint(
                      size: Size.infinite,
                      // 背景层：正文文本（含选区、光标）
                      painter: EditorPainter(
                        buffer: widget.buffer,
                        lineHeight: _m.lineHeight,
                        padding: _m.padding + _m.lineNumberWidth, // 留出行号栏
                        cursorPos: widget.controller.cursorPosition,
                        showCursor:
                        widget.caretBlinker.isVisible &&
                            widget.focusNode.hasFocus,
                        selectionStart: widget.controller.hasSelection
                            ? widget.controller.selectionStart
                            : null,
                        selectionEnd: widget.controller.hasSelection
                            ? widget.controller.selectionEnd
                            : null,
                        scrollY: _scrollY,
                        highlighter: widget.highlighter,
                        theme: widget.theme,
                      ),
                      // 前景层：行号与滚动条
                      foregroundPainter: LineNumberEditorPainter(
                        scrollY: _scrollY,
                        buffer: widget.buffer,
                        cursorPos: widget.controller.cursorPosition,
                        showCursor:
                        widget.caretBlinker.isVisible &&
                            widget.focusNode.hasFocus,
                        selectionStart: widget.controller.hasSelection
                            ? widget.controller.selectionStart
                            : null,
                        selectionEnd: widget.controller.hasSelection
                            ? widget.controller.selectionEnd
                            : null,
                        highlighter: widget.highlighter,
                        theme: widget.theme,
                        lineHeight: _m.lineHeight,
                        padding: _m.padding,
                        lineNumberWidth: _m.lineNumberWidth,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}
